// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.ui.database.editors;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.EventObject;

import org.dengues.commons.IDenguesCoreContants;
import org.dengues.core.CorePlugin;
import org.dengues.core.editor.AbstractGenericGEFEditor;
import org.dengues.core.resource.WarehouseResourceFactory;
import org.dengues.designer.ui.database.parts.DBEditPartFactory;
import org.dengues.designer.ui.editors.GEFEditorContextMenuProvider;
import org.dengues.designer.ui.editors.GEFEditorFreeformRootEditPart;
import org.dengues.designer.ui.editors.actions.GEFCopyAction;
import org.dengues.designer.ui.editors.actions.GEFCutAction;
import org.dengues.designer.ui.editors.actions.GEFDeleteAction;
import org.dengues.designer.ui.editors.actions.GEFPasteAction;
import org.dengues.designer.ui.editors.dnd.GEFEditorDropTargetListener;
import org.dengues.designer.ui.editors.palette.DBEditorPaletteFactory;
import org.dengues.designer.ui.i18n.Messages;
import org.dengues.designer.ui.properties.DenguesEditorTabbedPropertySheetPage;
import org.dengues.model.database.DatabaseDiagram;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.SnapToGrid;
import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.requests.SimpleFactory;
import org.eclipse.gef.ui.actions.SelectionAction;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.views.properties.IPropertySheetPage;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-13 qiang.zhang $
 * 
 */
public class GEFDatabaseEditor extends AbstractGenericGEFEditor {

    private boolean savePreviouslyNeeded;

    public static final String ID = "org.dengues.designer.databaseEditor"; //$NON-NLS-1$

    public static final String DEFAULT_EXTENSION = ".dbe"; //$NON-NLS-1$

    private static PaletteRoot paletteRoot;

    private DatabaseDiagram databaseDiagram;

    public static final int GRID_SIZE = 8;

    /**
     * Qiang.Zhang.Adolf@gmail.com GEFDatabaseEditor constructor comment.
     */
    public GEFDatabaseEditor() {
        super();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
     */
    @Override
    protected void configureGraphicalViewer() {
        super.configureGraphicalViewer();
        ScrollingGraphicalViewer viewer = (ScrollingGraphicalViewer) getGraphicalViewer();
        GEFEditorFreeformRootEditPart root = new GEFEditorFreeformRootEditPart(getEditorInput());
        root.setCommandStack(getCommandStack());
        viewer.setRootEditPart(root);
        viewer.setEditPartFactory(new DBEditPartFactory());
        viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));

        GEFDeleteAction deleteAction = new GEFDeleteAction(this);
        getActionRegistry().registerAction(deleteAction);
        getSelectionActions().add(deleteAction.getId());

        SelectionAction action = new GEFCopyAction(this);
        getActionRegistry().registerAction(action);
        getSelectionActions().add(action.getId());

        action = new GEFCutAction(this);
        getActionRegistry().registerAction(action);
        getSelectionActions().add(action.getId());

        action = new GEFPasteAction(this);
        getActionRegistry().registerAction(action);
        getSelectionActions().add(action.getId());

        ContextMenuProvider menuProvider = new GEFEditorContextMenuProvider(this, viewer, getActionRegistry());
        viewer.setContextMenu(menuProvider);
        getGraphicalViewer().setKeyHandler(new GraphicalViewerKeyHandler(getGraphicalViewer()).setParent(getCommonKeyHandler()));

        getGraphicalViewer().setProperty(SnapToGrid.PROPERTY_GRID_SPACING, new Dimension(GRID_SIZE, GRID_SIZE));
        getGraphicalViewer().setProperty(SnapToGrid.PROPERTY_GRID_ENABLED, new Boolean(true));
        // We keep grid visibility and enablement in sync
        getGraphicalViewer().setProperty(SnapToGrid.PROPERTY_GRID_VISIBLE, new Boolean(true));
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getDatabaseTitle".
     * 
     * @return
     */
    public String getDatabaseTitle() {
        return CorePlugin.getDefault().getDenguesTitle(
                ((DBFileEditorInput) getEditorInput()).getFile().getFullPath().toPortableString().substring(1));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#commandStackChanged(java.util.EventObject)
     */
    @Override
    public void commandStackChanged(EventObject event) {
        if (isDirty()) {
            if (!this.savePreviouslyNeeded) {
                this.savePreviouslyNeeded = true;
                firePropertyChange(IEditorPart.PROP_DIRTY);
            }
        } else {
            savePreviouslyNeeded = false;
            firePropertyChange(IEditorPart.PROP_DIRTY);
        }
        super.commandStackChanged(event);
    }

    /**
     * Create a transfer drop target listener. When using a CombinedTemplateCreationEntry tool in the palette, this will
     * enable model element creation by dragging from the palette.
     * 
     * @see #createPaletteViewerProvider()
     */
    private TransferDropTargetListener createTransferDropTargetListener() {
        return new TemplateTransferDropTargetListener(getGraphicalViewer()) {

            @Override
            protected CreationFactory getFactory(Object template) {
                return new SimpleFactory((Class) template);
            }
        };
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#getAdapter(java.lang.Class)
     */
    @Override
    public Object getAdapter(Class type) {
        if (type == IPropertySheetPage.class) {
            return new DenguesEditorTabbedPropertySheetPage(this);
        }
        return super.getAdapter(type);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)
     */
    @Override
    protected void setInput(IEditorInput input) {
        super.setInput(input);
        if (input instanceof DBFileEditorInput) {
            databaseDiagram = ((DBFileEditorInput) input).getDbDiagram();
            setPartName(databaseDiagram.getName());
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#initializeGraphicalViewer()
     */
    @Override
    protected void initializeGraphicalViewer() {
        super.initializeGraphicalViewer();
        getGraphicalViewer().setContents(databaseDiagram); // set the contents of this editor
        getGraphicalViewer().addDropTargetListener(createTransferDropTargetListener());
        getGraphicalViewer().addDropTargetListener(new GEFEditorDropTargetListener(this));
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public void doSave(IProgressMonitor monitor) {
        monitor.beginTask(Messages.getString("GEFDatabaseEditor.TaskName"), 100); //$NON-NLS-1$
        monitor.worked(10);
        try {
            ((DBFileEditorInput) getEditorInput()).getSqlScriptFile();
            WarehouseResourceFactory.save(getDatabaseDiagram());
            getCommandStack().markSaveLocation();
            setDirty(false);
            monitor.worked(10);
        } catch (Exception e) {
            e.printStackTrace();
            monitor.setCanceled(true);
        } finally {
            monitor.done();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#doSaveAs()
     */
    @Override
    public void doSaveAs() {
        // Show a SaveAs dialog
        Shell shell = getSite().getWorkbenchWindow().getShell();
        SaveAsDialog dialog = new SaveAsDialog(shell);
        dialog.setOriginalFile(((IFileEditorInput) getEditorInput()).getFile());
        dialog.open();

        IPath path = dialog.getResult();
        if (path != null) {
            // try to save the editor's contents under a different file name
            final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
            try {
                new ProgressMonitorDialog(shell).run(false, // don't fork
                        false, // not cancelable
                        new WorkspaceModifyOperation() { // run this operation

                            @Override
                            public void execute(final IProgressMonitor monitor) {
                                try {
                                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                                    file.create(new ByteArrayInputStream(out.toByteArray()), // contents
                                            true, // keep saving, even if IFile is out of sync with the Workspace
                                            monitor); // progress monitor
                                } catch (CoreException ce) {
                                    ce.printStackTrace();
                                } catch (Exception ioe) {
                                    ioe.printStackTrace();
                                }
                            }
                        });
                // set input to the new file
                setInput(new FileEditorInput(file));
                getCommandStack().markSaveLocation();
            } catch (InterruptedException ie) {
                // should not happen, since the monitor dialog is not cancelable
                ie.printStackTrace();
            } catch (InvocationTargetException ite) {
                ite.printStackTrace();
            }
        } // if
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
     */
    @Override
    public boolean isSaveAsAllowed() {
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#getPaletteRoot()
     */
    @Override
    protected PaletteRoot getPaletteRoot() {
        if (paletteRoot == null) {
            paletteRoot = DBEditorPaletteFactory.createPalette();
        }
        return paletteRoot;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.ui.parts.GraphicalEditor#selectionChanged(org.eclipse.ui.IWorkbenchPart,
     * org.eclipse.jface.viewers.ISelection)
     */
    @Override
    public void selectionChanged(final IWorkbenchPart part, final ISelection selection) {
        super.selectionChanged(part, selection);
        if (this.equals(part)) {
            updateActions(getSelectionActions());
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor#getContributorId()
     */
    public String getContributorId() {
        return IDenguesCoreContants.ID_VIEW_PROP;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getDatabaseDiagram".
     * 
     * @return
     */
    public DatabaseDiagram getDatabaseDiagram() {
        return databaseDiagram;
    }
}
